﻿// (c) Comkarl Calipso
// By Matías Fidemraizer (http://www.matiasfidemraizer.com)
// -------------------------------------------------
// http://calipso.codeplex.com
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using Comkarl.Web.Configuration;
using Comkarl.Web.Reflection;
using Comkarl.Web.Resources;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Linq.Expressions;

namespace Comkarl.Web.UI.Controls
{
    /// <summary>
    /// Represents a control which has a server and client part.
    /// </summary>
    /// <remarks>
    /// <h3>Quick links</h3>
    /// <list type="bullet">
    ///     <item><a href="#intro">1.0  Introduction to script controls</a></item>
    ///     <item><a href="#concepts">2.0  Concepts</a></item>
    ///     <item>
    ///         <a href="#clientinfrastructure">3.0  Understanding client infrastructure</a>
    ///         <list type="bullet">
    ///             <item><a href="#clientcontrolclass">3.1  Client script control class</a></item>
    ///             <item><a href="#clientcontrollifecycle">3.1  Client script control life-cycle</a></item>
    ///         </list>
    ///     </item>
    ///     <item>
    ///         <a href="#programming">4.0  Programming script controls</a>
    ///         
    ///         <list type="bullet">
    ///             <item><a href="#designingclientpart">4.1    Designing the client-side part of a script control</a></item>
    ///             <item><a href="#designingserverpart">4.2    Designing the server-side part of a script control</a></item>
    ///         </list>
    ///     </item>
    ///     <item><a href="#localization">5.0   Client-side string localization</a></item>
    ///     <item>
    ///         <a href="#proxy">6.0      RESTful proxying: safe data retrieval from Web browsers</a>
    ///         
    ///         <list type="bullet">
    ///             <item>
    ///                 <list type="bullet">
    ///                     <item><a href="#customproxy">6.1.1  Customizing requests and responses</a></item>
    ///                 </list>
    ///                 <a href="#callingproxies">6.2     Calling server proxies from the client side from script controls</a>
    ///             </item>
    ///         </list>
    ///     </item>
    ///     <item><a href="#controlvalidation">7.0     Control validation</a></item>
    ///     <item><a href="#clientproperties">8.0       Client properties: properties declared in the server side and transmitted to the client script control</a></item>
    /// </list>
    /// <br />
    /// <br />
    /// <a name="intro" />
    /// <h3>1.0     Introduction to script controls</h3>
    /// <para>A script control is a regular Web Forms control that derives <see cref="Comkarl.Web.UI.Controls.ScriptControl"/> base class.</para>
    /// 
    /// <para>Script controls are able of render HTML markup from the server side like any other server control. That is, a script control can be the container of other server controls, 
    /// either other script controls or regular Web Forms controls. For example, this would be done overriding CreateChildControls() method.</para>
    /// 
    /// <para>In the other hand, script controls, like regular ones, can render raw HTML markup by overriding RenderControl(HtmlTextWriter) method. In addition, 
    /// ASP.NET Calipso introduces other <see cref="RenderControl(System.Xml.XmlWriter)" /> method overload that allows script controls to write HTML markup using an XML writer, which is far better, because it ensures that output 
    /// will be a well-formed document. This is acquired by overriding <see cref="RenderControl(System.Xml.XmlWriter)" /> overload. Recommended way of rendering raw HTML is using a <see cref="RenderControl(System.Xml.XmlWriter)" />
    /// override, rather than standard <see cref="RenderControl(HtmlTextWriter)" /> overload.</para>
    /// 
    /// <para>But what makes ASP.NET Calipso unique is that script controls can have a client-side counterpart that is executed in the client Web browser and it is coded using standard JavaScript.</para>
    /// 
    /// <para>Client-side JavaScript script control is just a JavaScript class that derives other JavaScript class called <strong>Comkarl.Web.UI.Controls.Control</strong>. ASP.NET Calipso makes an intensive use of jOOPL 
    /// JavaScript library in order to leverage object-oriented programming in Web browsers (<a href="http://joopl.codeplex.com" target="_new">learn more about jOOPL!</a>).
    /// </para>
    /// <br />
    /// <br />
    /// <a name="concepts" />
    /// <h3>2.0     Concepts</h3>
    /// ASP.NET Calipso uses mostly existing Web Forms concepts, but it adds new ones that should be understood in order to leverage script control programming:
    /// 
    /// <list type="table">
    ///     <listheader><term>Concept</term><description>Explanation</description></listheader>
    ///     <item>
    ///         <term>Server-side code</term>
    ///         <description>Server-side code is the one developed in a .NET language like C# or Visual Basic .NET, and deployed and executed in the Web server (Internet Information Services).</description>
    ///     </item>
    ///     <item>
    ///         <term>Client-side code</term>
    ///         <description>Client-side code is that one developed using standard JavaScript and executed in Web browsers.</description>
    ///     </item>
    ///     <item>
    ///         <term>Server control</term>
    ///         <description>By default, a server control is a class that derives <strong>System.Web.UI.Controls.Control</strong> or any other that inherits it.</description>
    ///     </item>
    ///     <item>
    ///         <term>Client control</term>
    ///         <description>ASP.NET Calipso has an own infrastructure in the client-side Web browser platform. A client control is a one that derives <strong>Comkarl.Web.UI.Controls.Control</strong> JavaScript class.</description>
    ///     </item>
    ///     <item>
    ///         <term>Script control</term>
    ///         <description>A script control is a regular Web control that inherits <strong><see cref="ScriptControl"/></strong> server base control. Its main feature is that it can handle things in the server and client side.</description>
    ///     </item>
    ///     <item>
    ///         <term>Client property</term>
    ///         <description>A client property is a client-side JavaScript property that receives a value from the server-side counterpart of the script control.</description>
    ///     </item>
    ///     <item>
    ///         <term>Client object</term>
    ///         <description>A client objects is a client-side JavaScript object that is created from a server object. Client objects cannot have methods.</description>
    ///     </item>
    ///     <item>
    ///         <term>After-load script</term>
    ///         <description>An after-load scripts is a one executed when all about ASP.NET Calipso JavaScript infrastructure is fully-loaded. After-load scripts are defined by script controls in the server-side.</description>
    ///     </item>
    /// </list>
    /// <br />
    /// <br />
    /// <a name="clientinfrastructure" />
    /// <h3>3.0     Understanding client infrastructure</h3>
    /// <para>In order to develop script controls, it is very important to understand how client infrastructure works.</para>
    /// 
    /// <para>Client-side script controls are managed by a JavaScript class called <strong>Comkarl.Web.PageManager</strong>. Script controls have a life-cycle in the Web browser before they are ready to interact with them, and this is
    /// managed by the so-called <strong>Comkarl.Web.PageManager</strong> JavaScript class.
    /// </para>
    /// 
    /// <a name="clientcontrolclass" />
    /// <h4>3.1     Client script control class</h4>
    /// <para>Client-side JavaScript script control class (<strong>Comkarl.Web.UI.Controls.Control</strong>) has these members:</para>
    /// 
    /// <h5>Properties</h5>
    /// <list type="table">
    ///     <listheader><term>Name</term><description>Description</description></listheader>
    ///     <item>
    ///         <term>
    ///         name
    ///         </term>
    ///         <description>
    ///         Gets or sets an arbitrary control name. <strong>This is an infrastructure property and it is also a client property.</strong>
    ///         </description>
    ///     </item>
    ///     <item>
    ///         <term>validationRelations</term>
    ///         <description>Gets or sets a validation relations objects (<a href="#validationrelations">see validation relations for further details)</a>.</description>
    ///     </item>
    ///     <item>
    ///         <term>applicationPath</term>
    ///         <description>Gets or sets ASP.NET application relative path. <strong>This is an infrastructure property and it is also a client property.</strong></description>
    ///     </item>
    ///     <item>
    ///         <term>parentElementSelector</term>
    ///         <description>Gets or sets a CSS selector to some existing HTML element to which current control must be appended. <strong>This is an infrastructure property and it is also a client property.</strong></description>
    ///     </item>
    ///     <item>
    ///         <term>id</term>
    ///         <description>Gets or sets the server-side control identifier. <strong>This is an infrastructure property and it is also a client property.</strong></description>
    ///     </item>
    ///     <item>
    ///         <term>elementCssClass</term>
    ///         <description>Gets or sets a CSS class that is the one assigned to DOM element representing the control's container.<strong>This is an infrastructure property and it is also a client property.</strong></description>
    ///     </item>
    ///     <item>
    ///         <term>element</term>
    ///         <description>Gets the DOM element representing current control's container (f.e. a <c>DIV</c> element). <strong>Note that this property will work if <c>ControlElementCssClass</c> server property is 
    ///         correctly set in the server-side.</strong></description>
    ///     </item>
    ///     <item>
    ///         <term>resources</term>
    ///         <description>
    ///             Gets control's localization string resources as plain old JavaScript object (<a href="#localization">see script control localization for more info</a>).
    ///         </description>
    ///     </item>
    ///     <item>
    ///         <term>disabled</term>
    ///         <description>
    ///         Sets all control's inner elements in a way that user cannot interact with them. <strong>Note that this property will work if <c>ControlElementCssClass</c> server property is 
    ///         correctly set in the server-side.</strong>
    ///         </description>
    ///     </item>
    /// </list>
    /// 
    /// <h5>Methods</h5>
    /// <list type="table">
    ///     <listheader><term>Name</term><description>Description</description></listheader>
    ///     <item>
    ///         <term>getGlobalResources(name:string)</term>
    ///         <description>
    ///         Retrieves global string resources by name as a plain old JavaScript object (f.e. <c>this.GetGlobalResources("SharedWords")</c>). <a href="#localization">See script control localization for more info.</a>.
    ///         </description>
    ///     </item>
    ///     <item>
    ///         <term>resolvePath(path:string)</term>
    ///         <description>Given a relative path, it converts to an ASP.NET application-relative path.</description>
    ///     </item>
    ///     <item>
    ///         <term>postProxy(operationName:string, args:object, callback:function)</term>
    ///         <description>Calls a proxied operation. <a href="#proxyhelper">Please refer to proxy helper for further details</a></description>
    ///     </item>
    /// </list>
    /// 
    /// 
    /// <a name="clientcontrollifecycle" />
    /// <h4>3.2     Client script control life-cycle</h6>
    /// <list type="number">
    ///     <item>Web browser parses client infrastructure.</item>
    ///     <item>Web browser parses the client script control and its dependencies</item>
    ///     <item>Client PageManager is initialized.</item>
    ///     <item>Script controls are registered into the PageManager.</item>
    ///     <item>Script controls are instantiated into the PageManager.</item>
    ///     <item>Client PageManager calls <c>Render</c> method of all registered client script controls.</item>
    ///     <item>Client PageManager calls <c>Initialize</c> method of all registered client script controls.</item>
    ///     <item>Client PageManager sets read-state and calls after-load scripts.</item>
    /// </list>
    /// 
    /// <para>
    /// Note an important detail: differently than regular server-side ASP.NET Web Forms control or page life-cycle, <c>PageManager</c> calls <c>Render</c> before <c>Initialize</c>. 
    /// <strong>Why?</strong> In the client-side, Web browser-based applications, in order to bind events, initialize data and some other tasks against the control, the control itself 
    /// should be already rendered. That is why order has been inverted.
    /// </para>
    /// <br />
    /// <br />
    /// <a name="programming" />
    /// <h3>4.0    Programming script controls</h3>
    /// <para>
    /// Script controls are just regular Web controls that inherits <see cref="Comkarl.Web.UI.Controls.ScriptControl"/> server class. Any script control <strong>must</strong> have assigned the next properties with
    /// proper values (in some cases, value is given by overridding the property):
    /// </para>
    /// 
    /// <list type="table">
    ///     <listheader><term>Name</term><description>Explanation</description></listheader>
    ///     <item>
    ///         <term>ID</term>
    ///         <description>
    ///         It is the regular <c>ID</c> of any server control. It is absolutely mandatory. Assign it in design-time.
    ///         </description>
    ///     </item>
    ///     <item>
    ///         <term>CommonID</term>
    ///         <description>ASP.NET Calipso needs to identify a script control, both in server and client side in order to work properly. <c>CommonID</c> is shared for any script control instance of some specific type. 
    ///             This property must be overridden in a ScriptControl-derived class and it will return a string containing an unique identifier like "MyControl" or any other.
    ///         </description>
    ///     </item>
    ///     <item>
    ///         <term>ControlElementCssClass</term>
    ///         <description>
    ///         This property must be overridden and it will return a string containing a CSS class name. It is the CSS class name that must be added to the element that represents the container of the script control. 
    ///         <strong>ASP.NET Calipso does not automatically add assigned class name to the container, but it is declaratively done in code by the ScriptControl-derived class.</strong>
    ///         </description>
    ///     </item>
    /// </list>
    /// <br />
    /// <a name="designingclientpart" />
    /// <h4>4.1     Designing the client-side part of a script control</h4>
    /// <para>
    /// In this how-to JavaScript control will be required as a physical file stored in a folder called <strong>Scripts</strong> in the root of a ficticious ASP.NET Web Forms application.
    /// </para>
    /// 
    /// <h5>#1 step</h5>
    /// <para>First step is creating a JavaScript directory called <strong>Scripts</strong> in the root of ASP.NET Web Forms application, and later, create a blank JavaScript
    /// file called <strong>HelloWorld.js</strong> (i.e. relative location would be <strong>/Scripts/HelloWorld.js</strong>).</para>
    /// 
    /// <h5>#2 step</h5>
    /// <para>Second step is desinging the JavaScript class inside the newly-created <strong>HelloWorld.js</strong> file:</para>
    /// <code>
    /// // Register the namespace. This is equivalent to importing the namespace:
    /// $namespace.register("Samples");
    /// 
    /// // Now declare the class:
    /// $global.Samples.HelloWorldControl = $def({
    ///     // Constructor
    ///     $constructor: function() {
    ///     },
    ///     
    ///     // Methods and properties
    ///     $members: {
    ///         render: function() {
    ///         },
    ///         
    ///         initialize: function() {
    ///         }
    ///     },
    ///     $extends: $global.Comkarl.Web.UI.Controls.Control // Last parameter of $class.declare is the base class. That is, inheriting the base class.
    /// });
    /// </code>
    /// <para><c>render</c> and <c>initialize</c> are virtual methods. The act of declaring them in a derived class is overridding the methods.</para>
    /// 
    /// <h5>#3 step</h5>
    /// <para>Third step is saying "Hello world" in the browser. This is achieved by rendering a <c><span></span></c> element.</para>
    /// <code>
    /// $namespace.register("Samples");
    /// 
    /// $global.Samples.HelloWorldControl = $def({
    ///     // Constructor. Declare there a class field.
    ///     $constructor: function() {
    ///         this.$_.container = null;
    ///     },
    ///     $member: {
    ///         // Rendering a SPAN HTML element using jQuery...
    ///         render: function() {
    ///            // This creates a SPAN element.
    ///            this.$_.container = $("<span />");
    ///            // This assigns the CSS class to the span. Since this control
    ///            // simply renders a SPAN element, the element itself is the control's container.
    ///            this.$_.container.addClass(this.elementCssClass);
    ///            
    ///            // Assign "Hello world!" to the SPAN element:
    ///            this.$_.container.text("Hello world!");
    ///            
    ///            // Finally, append the SPAN element to the parent container (that is, some existing HTML element that will
    ///            // be the parent of HelloWorldControl and this last one will be rendered as child of parent one). 
    ///            // Use parentElementSelector client property!
    ///            $(this.parentElementSelector).append(this.$_.container);
    ///         },
    ///         
    ///         initialize: function() {
    ///             // Once control is fully rendered, bind a click event to the SPAN element that will 
    ///             // open a window.alert() saying "Hello world!" too:
    ///             var that = this;
    ///             
    ///             this.$_.container.on("click", function() {
    ///                 window.alert(that.$_.container.text());
    ///             });
    ///         }
    ///     },
    ///     $extends: $global.Comkarl.Web.UI.Controls.Control
    /// });
    /// </code>
    /// 
    /// <h5>#4 step</h5>
    /// <para>Finally, register the script control into the PageManager:</para>
    /// <code>
    /// $namespace.register("Samples");
    /// 
    /// $global.Samples.HelloWorldControl = $def({
    ///     $constructor: function() {
    ///         this.$_.container = null;
    ///     },
    ///     $members: {
    ///         render: function() {
    ///            this.$_.container = $("<span />");
    ///            this.$_.container.addClass(this.elementCssClass);
    ///            this.$_.container.text("Hello world!");
    ///            
    ///            $(this.parentElementSelector).append(this.$_.container);
    ///         },
    ///         
    ///         initialize: function() {
    ///             var that = this;
    ///             
    ///             this.$_.container.on("click", function() {
    ///                 window.alert(that.$_.container.text());
    ///             });
    ///         }
    ///     },
    ///     $extends: $global.Comkarl.Web.UI.Controls.Control
    /// });
    /// 
    /// // First parameter of RegisterControl method is the CommonID of the control, the second is the control class.
    /// $calispo$context.registerControl("HelloWorldControl", $global.Comkarl.Calipso.Controls.HelloWorldControl);
    /// </code>
    /// <br />
    /// <a name="designingserverpart" />
    /// <h4>4.2     Designing the server-side part of a script control</h4>
    /// <h5>#1 step</h5>
    /// <para>
    /// First step is creating the server-side part of a script control and that is designing a regular C# class that derives <see cref="Comkarl.Web.UI.Controls.ScriptControl"/>:
    /// </para>
    /// 
    /// <code>
    /// public class HelloWorldControl : Comkarl.Web.UI.Controls.ScriptControl
    /// {
    /// }
    /// </code>
    /// 
    /// <h5>#2 step</h5>
    /// <para>
    /// Secondly, override <strong>CommonID</strong> and <strong>ControlElementCssClass</strong>:
    /// </para>
    /// <code>
    /// public class HelloWorldControl : Comkarl.Web.UI.Controls.ScriptControl
    /// {
    ///     public override string CommonID 
    ///     {
    ///         get { return "HelloWorld"; }
    ///     }
    ///     
    ///     public override string ControlElementCssClass
    ///     {
    ///         get { return "helloworld-container";
    ///     }
    /// }
    /// </code>
    /// 
    /// <h5>#3 step</h5>
    /// <para>
    /// In the third place, add an include and reference to the client-side JavaScript part:
    /// </para>
    /// <code>
    /// public class HelloWorldControl : Comkarl.Web.UI.Controls.ScriptControl
    /// {
    ///     public override string CommonID 
    ///     {
    ///         get { return "HelloWorld"; }
    ///     }
    ///     
    ///     public override string ControlElementCssClass
    ///     {
    ///         get { return "helloworld-container";
    ///     }
    ///     
    ///     protected override void OnLoad(System.EventArgs e)
    ///     {
    ///         ID = "scHelloWorld";
    ///         
    ///         JavaScriptManager.RegisterInclude("Controls//HelloWorld", "/Scripts/HelloWorld.js");
    ///         JavaScriptManager.RegisterReference("Controls//HelloWorld");
    ///     }
    /// }
    /// </code>
    /// 
    /// <para>For further details about registering includes and references, please go to <see cref="Comkarl.Web.UI.JavaScriptManager" /> class reference.</para>
    /// 
    /// <h5>#4 step</h5>
    /// <para>Fourth step is registering server script control in some Master Page or regular page. In the case of regular pages, these <strong>must inherit Comkarl.Web.UI.Page class</strong></para>
    /// <code>
    /// <%@ Page Language="C#" Inherits="Comkarl.Web.UI.Page" %>
    /// <%@ Register Assembly="Samples" Namespace="Samples" TagPrefix="samples" %>
    /// <html>
    /// <head></head>
    /// <body>
    /// <form runat="server">
    ///     <div id="content">
    ///     </div>
    /// </form>
    /// </body>
    /// </html>
    /// </code>
    /// 
    /// <h5>#5 step</h5>
    /// <para>Fifth step is adding a JavaScriptManager server control to the server markup. This is a required and mandatory step because ScriptControl server and client side heavenly relies on JavaScriptManager class
    /// and client JavaScript dependencies:</para>
    /// <code>
    /// <%@ Page Language="C#" Inherits="Comkarl.Web.UI.Page" %>
    /// <%@ Register Assembly="Samples" Namespace="Samples" TagPrefix="samples" %>
    /// <html>
    /// <head>
    ///     // This is the JavaScriptManager control!
    ///     <calipso:JavaScriptManager ID="jsManager" CombineFileName="page.js" runat="server" />
    /// </head>
    /// <body>
    /// <form runat="server">
    ///     <div id="content">
    ///     </div>
    /// </form>
    /// </body>
    /// </html>
    /// </code>
    /// </remarks>
    /// 
    /// <h5>#6 step</h5>
    /// <para>Finally, sixth step is adding the HelloWorldControl server control to the server markup of the page:</para>
    /// <para>Other detail is any script control must give a value to <strong>JavaScriptManagerId</strong> and <strong>CssManagerId</strong>, which must be the identifier of some existing JavaScriptManager and CssManager controls instance, respectively.</para>
    /// <code>
    /// <%@ Page Language="C#" Inherits="Comkarl.Web.UI.Page" %>
    /// <%@ Register Assembly="Samples" Namespace="Samples" TagPrefix="samples" %>
    /// <html>
    /// <head>
    ///     <calipso:JavaScriptManager ID="cssManager" CombineFileName="page.css" runat="server" />
    ///     <calipso:JavaScriptManager ID="jsManager" CombineFileName="page.js" runat="server" />
    /// </head>
    /// <body>
    /// <form runat="server">
    ///     <div id="content">
    ///         <samples:HelloWorldControl ID="scHelloWorld" ParentElementSelector="div#content" JavaScriptManagerId="jsManager" CssManagerId="cssManager" runat="server" />
    ///     </div>
    /// </form>
    /// </body>
    /// </html>
    /// </code>
    /// <br />
    /// <br />
    /// <a name="localization" />
    /// <h3>5.0     Client-side string localization</h3>
    /// <para>ASP.NET Calipso supports an state-of-the-art feature: client-side string localization.</para>
    /// <para>In fact, ASP.NET Calipso still uses RESX resources, but it implements a build-time feature that compiles RESX files into plain JavaScript objects. <strong>Only global resources 
    /// </strong>are supported for client-side localization.</para>
    /// 
    /// <a name="localizationrules" />
    /// <h4>5.1     Some rules</h4>
    /// <list type="number">
    ///     <item>
    ///         Resources are selected by thread's culture (i.e. System.Threading.Thread.CurrentThread.CurrentUICulture).
    ///     </item>
    ///     <item>
    ///         Only global resources are allowed.
    ///     </item>
    ///     <item>
    ///         Global resources must be in <strong>App_GlobalResources</strong> special folder.
    ///     </item>
    ///     <item>
    ///         The RESX file must only contain strings.
    ///     </item>
    ///     <item>
    ///         The RESX file name must be the exact name of the control plus FULL culture name dot resx (i.e. <strong>MyResFile.en-US.resx</strong>).  <strong>Resources for default configured culture in Web.config or machine default one
    ///         must not contain the culture name. For example, if Web.config has <c><globalization uiCulture="en-US"/></c>, a resource file (RESX) containing US English string resources must not have culture name. For example,
    ///         <c>SomeName.resx</c> instead of <c>SomeName.en-US.resx</c>!</strong>
    ///         There is an exception (see the text just before these rules).
    ///     </item>
    ///     <item>
    ///         In order to reflect a change in a RESX file, ASP.NET project must be re-built in Visual Studio.
    ///     </item>
    /// </list>
    /// 
    /// <para>As pointed in a rule in the above listing, <strong>there is an exception for RESX file naming convention</strong>. That is, ASP.NET Calipso can handle global resources that are not tied to the control but it 
    /// can be shared across any script control. RESX file must be still called "SomeName.[culture].resx" (i.e. SomeName.en-US.resx)</para>
    /// 
    /// <h4>5.2     How to localize client-side script controls</h4>
    /// <para>Any JavaScript script control has a read-only property called <strong>get_Resources()</strong>. Such property returns a plain old JavaScript object (in fact, an associative array), and its properties are just the 
    /// localized strings in the control's RESX file:
    /// </para>
    /// <code>
    /// var helloWorldText = this.resources.HelloWorldText;
    /// 
    /// // or...
    /// 
    /// helloWorldText = this.resources["HelloWorldText"];
    /// </code>
    /// 
    /// <para><strong>resources</strong> property will always hold server culture-specific version of the whole string resources.</para>
    /// 
    /// <para>Actually, adding a localized string to some HTML element would be just:</para>
    /// <code>
    /// $("span#someIdentifier").text(this.resources).HelloWorldText);
    /// 
    /// // or...
    /// 
    /// $("input[type=text]#someInputIdentifier").val(this.resources.HelloWorldText);
    /// </code>
    /// <para><strong>NOTE: If there are no string resources for thread's culture, ASP.NET Calipso will build a blank resource object.</strong></para>
    /// 
    /// <h4>5.3     Working with client-side global resources</h4>
    /// <para>ASP.NET Calipso supports fully-global resources in the client side. That is, ones that are not tied to a specific control but it can be required by any.</para>
    /// <para>Client-side global resources are also server RESX files compiled into JavaScript files contaning plain old JavaScript objects. Main difference to control-specific resources is that global resource files do not have
    /// a naming restriction, but full-culture identifier suffixes are required yet. Some sample file names of global resource files:</para>
    /// <list type="bullet">
    ///     <item><strong>SharedWords.en-US.resx</strong></item>
    ///     <item><strong>ErrorMessages.en-US.resx</strong></item>
    ///     <item><strong>Buttons.en-US.resx</strong></item>
    /// </list>
    /// <para>Like control-specific resource files, global resource files (RESX) must be placed in ASP.NET <strong>App_GlobalResources</strong> special folder, and ASP.NET project should be re-built to reflect RESX changes in the client-side.</para>
    /// <para>An important point is that global resources are not available in the client-side by default, but script controls must require them in order to have them available. This is possible 
    /// by calling <see cref="RegisterResource" /> method in the server control code. For example, overridding <strong>OnInit(System.EventArgs)</strong> or <strong>OnLoad(System.EventArgs)</strong> methods:
    /// </para>
    /// <code>
    /// public void override OnLoad(System.EventArgs e)
    /// {
    ///     // Note that a global resource will be registered by its RESX file name WITHOUT culture suffix or file extension!
    ///     RegisterResource("SharedWords");
    /// }
    /// </code>
    /// <para>Later, in JavaScript code, in some script control, a global resource is accessed this way:</para>
    /// <code>
    /// var okText = this.getGlobalResources("SharedWords").OkText;
    /// 
    /// // ...or
    /// 
    /// okText =  this.getGlobalResources("SharedWords")["OkText"];
    /// </code>
    /// <para>In fact, using this API, there is no limitation on retrieving resources of some control as global resources. Just get its resources by control's type name in the server code (i.e. server control class name):</para>
    /// <code>var controlTitle = this.getGlobalResources("MyControlTypeName").Title;</code>
    /// <para><strong>NOTE: If there are no string resources for thread's culture, ASP.NET Calipso will build a blank resource object.</strong></para>
    /// <br/>
    /// <br/>
    /// <a name="proxy" />
    /// <h3>6.0     Web service proxying: safe data retrieval from Web browsers</h3>
    /// <para>Sometimes client-side JavaScript controls or classes require remote data and they need to call a Web service operation. There are Web service endpoints that requires authentications and others that exposes their API 
    /// to the public without authentication. Calling a public Web service API without authentication may be safe to be called from plain JavaScript, <strong>but this is not the case of ones that require authentication.</strong></para>
    /// <para>Web service authentication in many ones require an <strong>API key</strong> (a private secret) and/or credentials. In this case, since JavaScript and Web browsers do not have a safe, encrypted way of storing data, <strong>recommended
    /// approach is make the call to the Web Service API from server code.</strong></para>
    /// <para>Above code means that client-side JavaScript code must call a server operation, properly giving zero or more arguments to let server code call the Web service API with authentication using the API secret. <strong>This is creating
    /// a proxy, because server code receives a command with arguments and this is converted into other HTTP (or any protocol) request to some remote server.</strong> This is the way to go, because <strong>API secret remains secret!</strong></para>
    /// <para>
    /// ASP.NET Calipso provides a set of conventions and actual coding features to ease the task of proxying Web Service API operation calls thanks to client-side ScriptControl's <strong>CallProxy</strong> method and an HTTP handler that does
    /// the redirection from proxy calls to actual Web service API operations.
    /// </para>
    /// 
    /// <h4>6.1     The server proxy: creating and registering ASP.NET HTTP handler</h4>
    /// <h5>#1 step</h5>
    /// <para>First step is creating a regular HTTP handler that must inherit <strong>Comkarl.Web.ServiceProxyHandler</strong> abstract class. For this, create a new class file in the Visual Studio ASP.NET application project and make
    /// such class <strong>partial</strong>:</para>
    /// <code>
    /// // Change this namespace by project's one. This is for the sake of the sample.
    /// namespace Samples
    /// {
    ///     public sealed partial class ServiceProxyHandler : Comkarl.Web.ServiceProxyHandler
    ///     {
    ///         // Both OnPrepare and OnReceive are optionally overridden. These methods are the right
    ///         // place to customize the request and later the response, and manipulate the resulting object
    ///         // of the request. The object will depend on how proxy handles results. These methods will be discussed later.
    ///         
    ///         protected void override OnPrepare(System.Web.HttpContext context)
    ///         {
    ///         }
    ///         
    ///         protected void override OnReceive(System.Web.HttpContext context, object result)
    ///         {
    ///         }
    ///     }
    /// }
    /// </code>
    /// 
    /// <h5>#2 step</h5>
    /// <para>Finally, second step is registering the above HTTP handler in project's Web.config (<strong>important note: register it in the Web.config file rather than Web.Debug.config or Web.Release.config</strong>):</para>
    /// <code>
    /// <?xml version="1.0" encoding="utf-8"?>
    /// <configuration>
    ///   <system.webServer>
    ///         <handlers>
    ///             <add name="Calipso-ServiceProxyHandler" 
    ///                 verb="POST" 
    ///                 preCondition="integratedMode" 
    ///                 resourceType="Unspecified" 
    ///                 path="proxy" 
    ///                 type="Samples.ServiceProxyHandler" /> // "type" attribute must have the full type name (including namespace) of the HTTP handler created in #1 step!
    ///         </handlers>
    ///   </system.webServer>
    /// </configuration>
    /// </code>
    /// 
    /// <h6>Now what?</h6>
    /// <para>#1 and #2 steps of previous how-to were for creating the proxying infrastructure. In order proxy Web browser calls to some remote Web service API operation, create a new <strong>partial class</strong>
    /// in a new code file called <strong>SomeProxy</strong>, but call the class as <strong>ServiceProxyHandler</strong>:</para>
    /// <code>
    /// // Change this namespace by project's one. This is for the sake of the sample.
    /// namespace Samples
    /// {
    ///     public partial class ServiceProxyHandler
    ///     {
    ///     }
    /// }
    /// </code>
    /// <para>Above code listing "extends" <strong>project's ServiceProxyHandler class</strong>. In order to let ASP.NET Calipso own's ServiceProxyHandler base class route Web broswer calls to be handled, implement a
    /// <strong>private method called "HelloWorld". Proxy mehtod must be private, async and return <c>System.Threading.Tasks.Task<object></c></strong>. In addition, this method must accept a single dynamic-typed input parameter:</para>
    /// <code>
    /// namespace Samples
    /// {
    ///     public partial class ServiceProxyHandler
    ///     {
    ///         private async System.Threading.Tasks.Task<object> HelloWorld(dynamic inputs)
    ///         {
    ///             // Do stuff
    ///             return null;
    ///         }
    ///     }
    /// }
    /// </code>
    /// <para>Above code will be hit if Web browser requests "HelloWorld" proxy operation. Once a proxy operation hits, some custom code using an HTTP client (or any protocol client) will be sending requests to remote
    /// resources. Using API secrets, passwords, credentials or any other will be safe at this point if those are sent via secure SSL or TSL encrypted channels.</para>
    /// 
    /// <a name="customproxy" />
    /// <h5>6.1.0   Customizing requests and responses</h5>
    /// <para>Since this is a proxying approach, the HTTP proxy request and response will not know about others performed by the proxy itself. For example, if a proxy operation uses an HTTP client and calls a remote HTTP service API,
    /// remote operation may response with metadata (HTTP headers) and proxy class needs a way of extracting such metadata from the remote HTTP service operation and put it in the proxy response.
    /// <para>In order to manipulate proxy's HTTP requests and responses, <strong>ServiceProxyHandler base class provides two key virtual methods: OnPrepare and OnReceive</strong>:</para>
    /// <list type="table">
    ///     <listheader><term>Name</term><description>Description</description></listheader>
    ///     <item>
    ///         <term>OnPrepare(System.Web.HttpContext)</term>
    ///         <description>Override this method in order to manipulate the request context. For example, this could be a good place to modify thread's culture, or extract 
    ///         some cookie value, during an asynchronous operations (that is, proxy operations). <strong>It gives current HTTP context by argument.</strong></description>
    ///     </item>
    ///     <item>
    ///         <term>OnReceive(System.Web.HttpContext, object)</term>
    ///         <description>Override this method in order to manipulate proxy responses. For example, this could be a good place to append cookies, HTTP headers to the 
    ///         proxy response coming from the response of some remote HTTP service operation. <strong>It gives current HTTP context and the response object by argument</strong></description>
    ///     </item>
    /// </list>
    /// 
    /// <h6>OnPrepare sample</h6>
    /// <para>Changing current thread culture from a request cookie:</para>
    /// <code>
    /// protected override void OnPrepare(System.Web.HttpContext context) 
    /// {
    ///     HttpCookie cultureCookie = context.Request.Cookies["culture"];
    ///     int lcid = int.Parse(cultureCookie.Value);
    ///     
    ///     System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo(lcid);
    /// }
    /// </code>
    /// 
    /// <h6>OnReceive sample</h6>
    /// <para>Adding a header from a response object...</para>
    /// <code>
    /// protected override OnReceive(System.Web.HttpContext context, object result)
    /// {
    ///     // Using JSON.NET...
    ///     dynamic responseObject = JsonConvert.Deserialize((string)result);
    ///     
    ///     // Say remote HTTP service operation returned a JSON object which has a "Success" flag property
    ///     // and this result should be transmitted to the Web browser as part of proxy response...
    ///     context.Response.Headers.Add("Success", ((bool)responseObject.Success).ToString());
    /// }
    /// </code>
    /// 
    /// <a name="callingproxies" />
    /// <h4>6.2     Calling server proxies from the client side from script controls</h4>
    /// <para>Once there are one or more proxy server operations implemented, calling them from a script control is as easy as invoking <strong>PostProxy</strong> method.
    /// <strong>CallProxy takes three input parameters (these are listed in order and order is mandatory):</strong>
    /// </para>
    /// <list type="table">
    /// <listheader><term>Name</term><description>Description</description></listheader>
    /// <item>
    ///     <term><strong>operationName</strong></term>
    ///     <description>The exact name of the server proxy operation. <strong>It is case-sensitive.</strong></description>
    /// </item>
    /// <item>
    ///     <term><strong>args</strong></term>
    ///     <description>An inline object (or map) where property is argument name and value, the argument value (f.e. <c>{ name: "Matias", secondName: "Fidemraizer" }</c>). 
    ///     <strong>Argument names are case sensitive!</strong></description>
    /// </item>
    /// <item>
    ///     <term><strong>callback</strong></term>
    ///     <description>A function that takes an input parameter: JSON-deserialized response object. <strong>PostProxy method ALWAYS deserializes response objects!</strong></description>
    /// </item>
    /// </list>
    /// <para>Calling a proxy server operation "HelloWorld" from a script control that needs a person name and second name would look like this code:</para>
    /// <code>
    /// this.postProxy("HelloWorld", { name: "Matias", secondName: "Fidemraizer" }, function(response) {
    ///     // In this case, "response" argument will be an object containing a property "Text" contaning "Hello world, 
    ///     // Matias Fidemraizer!" that would be created in some remote Web service API operation:
    ///     var text = response.Text;
    ///     
    ///     window.alert(text);
    /// });
    /// </code>
    /// 
    /// <h5>6.2.1 Customizing requests to server proxy operations</h5>
    /// <para>
    /// Client-side JavaScript <strong>Comkarl.Web.UI.Controls.Control class</strong> has two virtual methods that can be easly overridden to manipulate and customize requests and responses from a single point:
    /// </para>
    /// 
    /// <list type="table">
    ///     <listheader><term>Name</term><description>Description</description></listheader>
    ///     <item>
    ///         <term>onProxyCall</term>
    ///         <description>It does not take any input parameter. This is invoked when <strong>PostProxy</strong> method is about to send a request to server proxy operation. It is a good point to append cookies 
    ///         (session identifiers, authentication tokens, ...).</description>
    ///     </item>
    ///     <item>
    ///         <term>addProxyPostPromises</term>
    ///         <description>
    ///         It takes a single input parameter. This input parameter is called <strong>jqXHR</strong>, which is a jQuery object implementing the <strong>Promise</strong> convention. 
    ///         <strong>This jqXHR object is good for adding additional handlers to the asynchronous operation like .done, .success, ...</strong>.
    ///         <a href="http://api.jquery.com/jQuery.ajax/" target="_new">Check official jQuery documentation on this for more info (scroll to "The jqXHR object"!)</a>
    ///         </description>
    ///     </item>
    ///     <item>
    ///         <term>onProxyCallEnd</term>
    ///         <description>It takes a single input parameter that is the response object when call to the server proxy operation ends. It is a good point to analyze the result and take generic actions like showing a common message 
    ///         saying "Last operation was successfully executed" or any other thing.</description>
    ///     </item>
    /// </list>
    /// 
    /// <h6>How to override them...</h6>
    /// <para>Since ASP.NET Calipso uses <a href="http://joopl.codeplex.com" target="_new">jOOPL library for object-oriented programming in JavaScript</a>, overridding such methods is just declaring one or all of them in a 
    /// <strong>Comkarl.Web.UI.Control</strong>-derived (i.e. a client-side part of a script control) class:</para>
    /// <code>
    /// $namespace.register("Samples");
    /// 
    /// $global.Samples.HelloWorldControl = $def({
    ///     $constructor: function() {
    ///     },
    ///     $members: {
    ///         onProxyCall: function() {
    ///             // Adds a DIV at the beggining of the HTML document 
    ///             // with the text "Asynchronous operation has started!"
    ///             // in order to notify the user that operation started.
    ///             var notifyUI = $("<div />");
    ///             notifyUI.text("Asynchronous operation has started!");
    ///             notifyUI.preppendTo(document.body);
    ///         },
    ///         
    ///         addProxyPostPromises: function(jqXHR) {
    ///             // Adds a jQuery $.ajax .done handler that
    ///             // alerts "Operation done!" when asynchronous operation
    ///             // has been done.
    ///             jqXHR.done(function() {
    ///                 alert("Operation done!");
    ///             });
    ///         },
    ///         
    ///         onProxyCallEnd: function(response) {
    ///             // Opens a "window.alert" showing the text
    ///             // coming in the response object.
    ///             window.alert(response.Text);
    ///         },
    ///         
    ///         render: function() {
    ///         },
    ///         
    ///         initialize: function() {
    ///             this.callProxy("HelloWorld", { name: "Matias", secondName: "Fidemraizer" }, function(response) {
    ///             });
    ///         }
    ///     },
    ///     $extends: Comkarl.Web.UI.Controls.Control
    /// );
    /// 
    /// $calipso$context.registerControl("HelloWorldControl", $global.Comkarl.Calipso.Controls.HelloWorldControl);
    /// </code>
    /// <para>Other option would be creating a base class that overrides these proxy-related methods in order to let any derived class share a common behavior
    /// when working with server proxy operations!</para>
    /// <code>
    /// $namespace.register("Samples");
    /// 
    /// $global.Samples.BaseClass = $def({
    ///     $constructor: function() {
    ///     },
    ///     $members: {
    ///         onProxyCall: function() {
    ///             // Adds a DIV at the beggining of the HTML document 
    ///             // with the text "Asynchronous operation has started!"
    ///             // in order to notify the user that operation started.
    ///             var notifyUI = $("<div />");
    ///             notifyUI.text("Asynchronous operation has started!");
    ///             notifyUI.preppendTo(document.body);
    ///         },
    ///         
    ///         addProxyPostPromises: function(jqXHR) {
    ///             // Adds a jQuery $.ajax .done handler that
    ///             // alerts "Operation done!" when asynchronous operation
    ///             // has been done.
    ///             jqXHR.done(function() {
    ///                 alert("Operation done!");
    ///             });
    ///         },
    ///         
    ///         onProxyCallEnd: function(response) {
    ///             // Opens a "window.alert" showing the text
    ///             // coming in the response object.
    ///             window.alert(response.Text);
    ///         }
    ///     },
    ///     $extends: $global.Comkarl.Web.UI.Controls.Control
    /// );
    /// 
    /// $global.Samples.HelloWorldControl = $def({
    ///     $constructor: function() {
    ///     },
    ///     $members: {
    ///         render: function() {
    ///         },
    ///         
    ///         initialize: function() {
    ///             this.callProxy("HelloWorld", { name: "Matias", secondName: "Fidemraizer" }, function(response) {
    ///             });
    ///         }
    ///     },
    ///     $extends: Samples.BaseClass 
    ///     // It is that easy! Just inherit a base class that already inherits 
    ///     // Comkarl.Web.UI.Controls.Control and that is all!
    /// );
    /// 
    /// $calipso$context.registerControl("HelloWorldControl", $global.Comkarl.Calipso.Controls.HelloWorldControl);
    /// </code>
    /// <br/><br/>
    /// <a name="controlvalidation" />
    /// <h3>7.0     Control validation</h3>
    /// <para>ASP.NET Calipso does not provide an actual client-side validation system. This is delegated to more focused on validation developments like jQuery plug-ins and others. But it provides a set of conventions
    /// for expressing errors coming from server proxy operations (and others) in order to leverage a way of marking HTML elements that are related to some error with CSS classes.</para>
    /// <para>This approach can become very powerful when combined with specific libraries and good styling.</para>
    /// <para>One important detail is that in order to leverage what ASP.NET Calipso offers, both client and server components should be in tune in terms of following some conventions</para>
    /// 
    /// <a name="validationresults" />
    /// <h4>7.1     How does control validation results work on script controls</h4>
    /// <para>Control validation is based in some conventions. Either can work for proxy calls or others, but this explanation is focused on proxy calls.</para>
    /// <para>These conventions apply to server proxy call operation response object that receives <strong>PostProxy</strong> callback in client-side JavaScript script controls:</para>
    /// <list type="bullet">
    ///     <item><strong>Response object will contain a property called "Errors" or "errors"</strong></item>
    ///     <item><strong>"Errors" o "errors" property must contain a property called "AffectedResources" or "affectedResources"</strong></item>
    ///     <item><strong>"AffectedResources" or "affectedResources" property must be an object (i.e. associative array).</strong></item>
    ///     <item><strong>The "AffectedResources" or "affectedResources" object must contain one or mroe properties, where property identifier is camel or hungarian-cased (WITHOUT SPACE CHARACTERS) of what failed, and 
    ///     property value is a human-readable reason text (string).</strong></item>
    /// </list>
    /// <para>Once response object follows above convention, any client-side JavaScript <strong>Comkarl.Web.UI.Controls.Control</strong>-derived class has <strong>set_ValidationRelations</strong> property that configures the mapping
    /// of CSS selectors and affected resources contained in response objects.</para>
    /// 
    /// <h5>What is an "affected resource"?</h5>
    /// <para>An affected resource is something that did wrong in a server proxy operation call. It is identified by a name and it provides a text explaining what happen in order to notify proper info to the user.</para>
    /// 
    /// <h5>set_ValidationRelations script control property explained</h5>
    /// <para>This write-only property sets an object (i.e. associative array), where the property name is the identifier of a possible affected resource, and its value is a CSS selector as string:</para>    
    /// <code>
    /// $namespace.register("Samples");
    /// 
    /// $global.Samples.HelloWorldControl = $def({
    ///     $constructor: function() {
    ///     },
    ///     $members: {
    ///         render: function() {
    ///         },
    ///         
    ///         initialize: function() {
    ///             this.set_ValidationRelations({
    ///                 "Name" : "div#content input[type=text]#name",
    ///                 "SecondName" : "div#content input[type=text]#second-name"
    ///             });
    ///         }
    ///     },
    ///     $extends: Comkarl.Web.UI.Controls.Control
    /// });
    /// 
    /// $calipso$context.registerControl("HelloWorldControl", $global.Comkarl.Calipso.Controls.HelloWorldControl);
    /// </code>
    /// 
    /// <h6>But... What does it mean "Name", "SecondName" in above code...?</h6>
    /// <para>"Name" and "SecondName" affected resources would be, for example, a "Name" and "SecondName" of a C# or Visual Basic .NET class property that did not validate against
    /// some business validation system, and following ASP.NET Calipso response object conventions, returned a set of two affected resources that did not validate.</para>
    /// 
    /// <h6>Validation relations are configured and response object follows above conventions. What now?</h6>
    /// <para>
    /// ASP.NET Calipso implements a very simple way of notifying affected resources that consists in adding a <c>DIV</c> element just after the mapped HTML element in validation relations. Such
    /// <c>DIV</c> is added with a CSS class called <strong>.brokenfield-info</strong> and it contains the reason text that came with the affected resource in the response object errors.
    /// </para>
    /// <para>Aditionally to above statement, ASP.NET Calipso adds <strong>.brokenfield</strong> class to the selected HTML element by the validaton relation CSS selector of the affected resource.</para>
    /// <para>There is no default styles for both CSS classes (<strong>.brokenfield</strong> and <strong>.brokenfield-info</strong>).</para>
    /// <para>The so-called <strong>.brokenfield</strong> CSS class is intended to be added to HTML elements that can have a background color, image or a border, and let CSS stylesheet set an error color
    /// like red or orange to these elements, letting users know that something went wrong and it was because some invalid input.</para>
    /// 
    /// <h6>How to alter default behavior of adding the <c>DIV</c> after the affected resource</h6>
    /// <para>In order to alter how each affected resource renders something notifying the user about an affected resource (or just for the sake of creating an additional HTML element like a tooltip or anyhow),
    /// <strong>Comkarl.Web.UI.Controls.Control</strong> JavaScript class (the base class of any script control in the client-side)
    /// provides a virtual method called <strong>RenderValidatedResource</strong> that can be overridden in order to alter or absolutely change default behavior:
    /// </para>
    /// <code>
    /// $namespace.register("Samples");
    /// 
    /// $global.Samples.HelloWorldControl = $def({
    ///     $constructor: function() {
    ///     },
    ///     $members: {
    ///         render: function() {
    ///         },
    ///         
    ///         initialize: function() {
    ///             this.validationRelations = {
    ///                 "Name" : "div#content input[type=text]#name",
    ///                 "SecondName" : "div#content input[type=text]#second-name"
    ///             };
    ///         },
    ///         
    ///         renderValidatedResource(affectedResourceId, reasonText) {
    ///             // Comment next code line if default behavior must be avoided (completely removed)
    ///             this.$_.$base.renderValidatedResource(affectedResourceId, reasonText); 
    ///             
    ///             // Opens a browser alert "[SomeAffectedResourceId] has failed. Reason: 'It failed because....'
    ///             window.alert(affectedResourceId + " has failed. Reason: '" + reasonText + "'.");
    ///         }
    ///     },
    ///     $extends: $global.Comkarl.Web.UI.Controls.Control
    /// );
    /// 
    /// $calipso$context.registerControl("HelloWorldControl", $global.Comkarl.Calipso.Controls.HelloWorldControl);
    /// </code>
    /// 
    /// <a name="pureclientcontrolvalidation" />
    /// <h4>7.2     Purely client-side control validation</h4>
    /// <para>
    /// Aditionally to the case use of setting validation relations and using affected resource user interface validation tied to <strong>PostProxy</strong> method, same mechanism can be
    /// used fully in client-side.
    /// </para>
    /// <para>At the end of the day, <strong>PostProxy</strong> calls <strong>ValidateRelations</strong> method also part of <strong>Comkarl.Web.UI.Controls.Control</strong>-derived JavaScript classes. That is,
    /// <strong>ValidateRelations</strong> can be called alone by giving an object that follows the so-called conventions (<a href="#validationresults">click here to see them again</a>):</para>    
    /// <code>
    /// $namespace.register("Samples");
    /// 
    /// $global.Samples.HelloWorldControl = $def({
    ///     $constructor: function() {
    ///     },
    ///     $members: {
    ///         render: function() {
    ///             var container = $("<span />");
    ///             container.addClass(this.elementCssClass);
    ///             container.attr("id", "text");
    ///             container.text("hello world!");
    ///             $(this.parentElementSelector).append(container);
    ///             
    ///             // This will set .brokenfield class into the rendered SPAN
    ///             // and it will render a DIV just after the SPAN saying
    ///             // "Sorry, you did not give a name! Try again!"
    ///             this.validationRelations = {
    ///                 errors : {
    ///                     affectedResources: {
    ///                         "Name": "Sorry, you did not give a name! Try again!"
    ///                     }
    ///                 }
    ///             };
    ///         },
    ///         
    ///         initialize: function() {
    ///             // Setting the mapping of a "Name" affected resource and a CSS selector
    ///             // to rendered SPAN element in the Render() method
    ///             this.validationRelations = {
    ///                 "Name" : "div#content span#text",
    ///             };
    ///         }
    ///     },
    ///     $extends: $global.Comkarl.Web.UI.Controls.Control
    /// });
    /// 
    /// $calispo$context.registerControl("HelloWorldControl", $global.Comkarl.Calipso.Controls.HelloWorldControl);
    /// </code>
    /// <br/><br/>
    /// 
    /// <a name="clientproperties" />
    /// <h3>8.0     Client properties</h3>
    /// <para>ASP.NET Calipso supports a way of transmit server script control properties' to its client-side counterpart. Or just set client-side properties from the server side.</para>
    /// <para>ScriptControl server class has a virtual method called <c>AddClientProperties</c> becoming the right place to do the binding. In the other hand, the same class exposes
    /// a property called <c>ClientProperties</c>, which is a collection of client properties.</para>
    /// 
    /// <h4>Conventions</h4>
    /// In order to let server code set client-side properties, client-side script controls must implement at least a setter function following the convention of prefixing getters with <strong>get_</strong> and
    /// <strong>set_</strong> the setters.
    /// 
    /// <h4>How-to: Creating a client property</h4>
    /// First of all, add a getter and setter function to the client-side, JavaScript script control:
    /// <code>
    ///$namespace.register("Samples");
    ///
    /// $global.Samples.SampleControl = $def({
    ///     $constructor: function() {
    ///         this.$_.name = null;
    ///     },
    ///     $members: {
    ///         get_Name: function() {
    ///             return this.$_.name;
    ///         },
    ///         set_Name: function(value) {
    ///             this.$_.name = value;
    ///         }
    ///     },
    ///     $extends: $global.Comkarl.Web.UI.Controls.Control
    /// });
    /// </code>
    /// 
    /// Secondly, implement a <strong>Name</strong> property in server script control's code:
    /// <code>
    /// public class SampleControl : Comkarl.Web.UI.Controls.ScriptControl
    /// {
    ///         public string Name { get; set; }
    /// }
    /// </code> 
    /// <para>In third place, override <c>AddClientProperties</c>. Client properties are created adding instances of Comkarl.Web.ClientProperty class to ScriptControl.ClientProperties collection:</para>
    /// <code>
    /// public class SampleControl : Comkarl.Web.UI.Controls.ScriptControl
    /// {
    ///         public string Name { get; set; }
    ///         
    ///         protected override void AddClientProperties()
    ///         {
    ///                 ClientProperty clientName = new ClientProperty();
    ///                 // Any client property must have an unique identifier. It must be inmutable across requests. Don't use Guid.NewGuid()!
    ///                 clientName.Id = Guid.Parse("3433c329-6799-4fa1-9142-19a3bbadc141");
    ///                 // Set the name of client-side JavaScript property without "get_" or "set_" preffix.
    ///                 clientName.Name = "Name";
    ///                 // Set the value of the property. Note that, in fact, there is no need of setting the value from an actual property, meaning
    ///                 // that it could perfectly be clientName.Value = "John";
    ///                 clientName.Value = Name;
    ///         }
    /// }
    /// </code> 
    /// <para><strong>If client-side code has a setter called <c>set_Name</c> and this is correctly implemented in order to set a class field holding Name's value, <c>get_Name</c> Name's getter will retrieve the whole
    /// server assigned value!</strong></para>
    /// </remarks>
    public abstract class ScriptControl : WebControl
    {
        public ScriptControl()
        {
            _clientProperties = new Lazy<List<ClientProperty>>(() => new List<ClientProperty>());
        }

        private readonly Lazy<List<ClientProperty>> _clientProperties;

        /// <summary>
        /// Gets or sets the JavaScriptManager control identifier (ID) that must manage control's dependencies. It can be a JavaScriptManager identifier
        /// of current page or a master page.
        /// </summary>
        public virtual string JavaScriptManagerId
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the CssManager control identifier (ID) that must manage control's dependencies. It can be a CssManager identifier
        /// of current page or a master page.
        /// </summary>
        public virtual string CssManagerId
        {
            get;
            set;
        }

        /// <summary>
        /// Gets current JavaScript manager.
        /// </summary>
        public JavaScriptManager JavaScriptManager
        {
            get
            {
                JavaScriptManager manager = CurrentPage.FindControlsRecursive<JavaScriptManager>(CurrentPage).Where(control => control.ID == JavaScriptManagerId).LastOrDefault();

                if (manager == null)
                {
                    throw new NullReferenceException(string.Format("No JavaScriptManager was found with the identifier '{0}'", JavaScriptManagerId));
                }

                return manager;
            }
        }

        /// <summary>
        /// Gets current CSS manager.
        /// </summary>
        public CssManager CssManager
        {
            get
            {
                CssManager manager = CurrentPage.FindControlsRecursive<CssManager>(CurrentPage).Where(control => control.ID == CssManagerId).LastOrDefault();

                if (manager == null)
                {
                    throw new NullReferenceException(string.Format("No CssManager was found with the identifier '{0}'", CssManagerId));
                }

                return manager;
            }
        }

        /// <summary>
        /// In derived classes, must contain the client-side HTML element CSS class.
        /// </summary>
        protected virtual string ControlElementCssClass
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        /// <summary>
        /// Gets or sets a CSS selector that points to the client-side HTML element to
        /// which current control must be appended to.
        /// </summary>
        public string ParentElementSelector
        {
            get;
            set;
        }

        protected abstract string ClientNamespace
        {
            get;
        }

        /// <summary>
        /// Gets a list of client properties.
        /// </summary>
        protected List<ClientProperty> ClientProperties
        {
            get
            {
                return _clientProperties.Value;
            }
        }

        /// <summary>
        /// Gets the client property set script format.
        /// </summary>
        private string ClientPropertySetScriptFormat
        {
            get
            {
                return Assembly.GetAssembly(typeof(WebControl)).GetEmbeddedResourceAsString("Comkarl.Web.UI.ClientScripts.ClientPropertySetTemplate.js");
            }
        }

        /// <summary>
        /// Gets if current control has client properties.
        /// </summary>
        protected bool HasClientProperties
        {
            get
            {
                return _clientProperties.IsValueCreated && _clientProperties.Value.Count > 0;
            }
        }

        /// <summary>
        /// In derived classes, provides if control's dependencies should be treated as standalone references.
        /// </summary>
        /// <remarks>
        /// This property should be overridden if localized resources should not be combined into the same file of
        /// the JavaScript control counterpart.
        /// </remarks>
        public virtual bool Standalone
        {
            get
            {
                return false;
            }
        }

        /// <summary>
        /// Registers a JavaScript-compiled RESX file of localized strings for the current culture.
        /// </summary>
        /// <param name="name">The resource file name without extension and culture identifiers (f.e. "Labels").</param>
        /// <param name="standalone">Gives a boolean that specifies if it should be registered as a standalone reference.</param>
        protected void RegisterResource(string name, bool standalone = false)
        {
            string resourceFileName = FileNameUtility.ChangeVersionInName(string.Format("{0}.{1}*.js", name, CultureInfo.CurrentUICulture.Name), CalipsoSection.Current.JavaScriptManager.CacheVersion);
            FileInfo resourceFile = new DirectoryInfo(RuntimeEnvironment.JsResourceAbsolutePath).GetFiles(resourceFileName).FirstOrDefault();

            if (resourceFile != null)
            {
                string resourceId = "Resources//" + CultureInfo.CurrentUICulture.Name + "|" + name;

                JavaScriptManager.RegisterInclude
                (
                    resourceId,
                    Path.Combine(RuntimeEnvironment.JsResourceRelativePath, resourceFile.Name),
                    ResourceKind.File
                );

                JavaScriptManager.RegisterReference(resourceId, standalone);
            }
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            RegisterResource(GetType().Name, Standalone);
        }

        protected virtual void RegisterClientProperties()
        {
            AddClientProperties();

            if (HasClientProperties)
            {
                string scriptFormat = ClientPropertySetScriptFormat;

                Guid someUniqueId = Guid.Empty;

                StringBuilder tempPropertySets = new StringBuilder();

                foreach (ClientProperty property in ClientProperties)
                {
                    someUniqueId = property.Id;
                    tempPropertySets.AppendFormat(@"args.control.{0} = ""{1}"";", arg0: property.Name, arg1: property.Value.ToString().Replace("\"", "\\\""));
                    tempPropertySets.AppendLine();
                }

                string tempScript =
                    scriptFormat.Replace("controlId", CommonID)
                    .Replace("expression", tempPropertySets.ToString());

                JavaScriptManager.RegisterAfterLoadScript(string.Format("{0}.{1}.{2}", CommonID, ID, someUniqueId.ToString().Replace("-", string.Empty)), tempScript, Standalone);
            }
        }

        protected virtual void RegisterClientSide()
        {
            JavaScriptManager.ControlRegisterScripts.Add
            (
                string.Format
                (
                    "$calipso$manager.registerControl(\"{0}\", $global.{1}.{2});",
                    CommonID,
                    ClientNamespace,
                    CommonID
                )
            );
        }

        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            RegisterClientProperties();
            RegisterClientSide();
        }

        public void AddClientProperty(Guid uniqueId, string propertyName, object propertyValue)
        {
            ClientProperties.Add(new ClientProperty { Id = uniqueId, Name = propertyName, Value = propertyValue });
        }

        /// <summary>
        /// In derived classes, adds client properties to current control. Derived classes should call this base implementation in order 
        /// to maintain some built-in features.
        /// </summary>
        protected virtual void AddClientProperties()
        {
            AddClientProperty(new Guid("BB626750-79DA-49FA-BD98-CDECEB5D2B03"), "ElementCssClass", ControlElementCssClass);

            if (!string.IsNullOrEmpty(ParentElementSelector))
            {
                AddClientProperty(Guid.Parse("60D825B0-FB23-4B16-A4D2-DB591CF6FFF1"), "ParentElementSelector", ParentElementSelector);
            }

            AddClientProperty(Guid.Parse("27993FAF-CB72-4d3e-B069-DFCBCC02BF21"), "ApplicationPath", Context.Request.ApplicationPath);
            AddClientProperty(Guid.Parse("d5638c5c-ca85-4226-b2bf-ccae6f024ff7"), "Name", GetType().Name);
        }
    }
}